package ccm.communicate.common;

import ccm.common.*;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

abstract public class Communicate implements Configurable
{
    protected ReceiveDataListener[][] receiveDataListener;
    protected StatusChangeListener    statusChangeListener;

    public Communicate()
    {
        this(1);
    }

    public Communicate(int channelNum)
    {
        receiveDataListener=new ReceiveDataListener[channelNum][];
        for(int i=0;i<receiveDataListener.length;++i)
            receiveDataListener[i]=new ReceiveDataListener[16];
    }

    /**
     * 启动
     */
    abstract public void start();

    /**
     * 停止
     */
    abstract public void stop();

    /**
     * 检查是否开启
     *
     * @return true表示开启
     * false表示关闭
     */
    abstract public boolean isOpen();

    /**
     * 发送数据
     *
     * @param data 数据
     * @throws NotStartException   未启动时抛出此异常
     * @throws SendFailedException 发送失败时抛出此异常
     * @implNote 默认使用0通道发送
     */
    public void send(byte[] data) throws NotStartException, SendFailedException
    {
        send(data,0);
    }

    /**
     * 发送数据
     *
     * @param data    数据
     * @param channel 通道
     * @throws NotStartException   未启动时抛出此异常
     * @throws SendFailedException 发送失败时抛出此异常
     * @implNote 通道未使用
     */
    abstract public void send(byte[] data,int channel) throws NotStartException, SendFailedException;

    /**
     * 删除一个接收数据监听器
     *
     * @param listener 监听器
     * @param channel  通道
     * @implNote 只支持一个监听器
     */
    public void removeReceiveDataListener(ReceiveDataListener listener,int channel)
    {
        if(listener==null)
            return;
        if(channel<0||channel>=receiveDataListener.length)
            return;
        for(int i=0;i<receiveDataListener[channel].length;++i)
            if(receiveDataListener[channel][i]==listener)
            {
                receiveDataListener[channel][i]=null;
                return;
            }
    }

    protected void callReceiveDataListener(int channel,ReceiveDataEvent event)
    {
        if(channel>=0&&channel<=receiveDataListener.length)
            for(int i=0;i<receiveDataListener[channel].length;++i)
                if(receiveDataListener[channel][i]!=null)
                    receiveDataListener[channel][i].receiveData(event);
    }

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @throws TooManyListenerException 监听器过多时抛出此异常
     * @throws NullPointerException     监听器为null时抛出此异常
     * @implNote 默认添加到通道0
     * 只支持一个监听器
     */
    public void addReceiveDataListener(ReceiveDataListener listener) throws TooManyListenerException, NullPointerException
    {
        addReceiveDataListener(listener,0);
    }

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @param channel  通道
     * @throws TooManyListenerException 监听器过多时抛出此异常
     * @throws NullPointerException     监听器为null时抛出此异常
     * @implNote 只支持一个监听器
     */
    public void addReceiveDataListener(ReceiveDataListener listener,int channel) throws TooManyListenerException, NullPointerException
    {
        if(listener==null)
            throw new NullPointerException();
        if(channel<0||channel>=receiveDataListener.length)
            throw new TooManyListenerException();
        for(int i=0;i<receiveDataListener[channel].length;++i)
            if(receiveDataListener[channel][i]==null)
            {
                receiveDataListener[channel][i]=listener;
                return;
            }
        throw new TooManyListenerException();
    }

    /**
     * 添加状态变化监听器
     *
     * @param listener 监听器
     * @throws TooManyListenerException 监听器过多时抛出此异常
     * @throws NullPointerException     监听器为null时抛出此异常
     * @implNote 只支持一个监听器
     */
    public void addStatusChangeListener(StatusChangeListener listener) throws TooManyListenerException, NullPointerException
    {
        if(listener==null)
            throw new NullPointerException();
        if(statusChangeListener!=null)
            throw new TooManyListenerException();
        statusChangeListener=listener;
    }

    /**
     * 状态变化时调用监听器
     *
     * @param reason 状态变化的原因
     */
    protected void statusChange(int reason)
    {
        if(statusChangeListener!=null)
            statusChangeListener.statusChange(new StatusChangeEvent(this,reason));
    }

    /**
     * 用于保存参数
     */
    abstract public void writeExternal(ObjectOutput out) throws IOException;

    /**
     * 用于加载参数
     */
    abstract public void readExternal(ObjectInput in) throws IOException;
}
